---
sidebar_position: 4
title: "Disable/Enable Hotkeys"
---

# Disable/Enable Hotkeys

We are now able to register our hotkeys, scope them to the component (or part of a component) and prevent stale state
inside our callback. But our hotkeys are always active. If the component has received focus, it will always trigger. However,
sometimes we want to dynamically decide if the hotkey should even be enabled.

There are multiple ways to disable a hotkey. Let's go through all of them.

## Dynamically disable or enable

### Toggle hotkeys with the `enabled` flag

Using the `enabled` flag in the options object, we can dynamically tell `useHotkeys` if the hotkey should be active or not.

```jsx
function ExampleComponent() {
  const [enabled, setEnabled] = useState(false)
  const [count, setCount] = useState(0)
  useHotkeys('b', () => setCount(prevCount => prevCount + 1), {
    enabled,
  })

  return (
    <div>
      <button onClick={() => setEnabled(prevValue => !prevValue)}>Toggle Hotkey</button>
      <p>Hotkey is {!enabled && 'not'} enabled.</p>
      <p>Pressed the 'b' key {count} times.</p>
    </div>
  )
}
```

This is useful to programmatically decide (depending on some internal state of our app or user input) if the hotkey
should be active or not.

:::info Tip
If we use the returned `ref` of the callback to scope our hotkey to a specific sub-tree of our component, note that
this will automatically activate or deactivate our hotkey depending on which part of the page has active focus.
:::

***

## Prevent default browser behavior

Some hotkeys like `ctrl + s` are already assigned to a browser function, in this case saving a website to
the users local disk. Sometimes we want to override these hotkeys to implement our own functionality. Maybe we want to
build a text editor or some other user based creation tool that needs a save shortcut to save the current progress. It
would be silly to introduce a new shortcut for saving the users progress, since every user knows that `ctrl + s` is the
universal shortcut for saving.

Our callback receives the browsers native event object, so we can just prevent the default behavior there and set up our
own custom handler:

```jsx
function ExampleComponent() {
  useHotkeys('cmd+s, ctrl+s', (e) => {
    e.preventDefault()

    alert('We saved your progress!')
    // ... set up our own saving dialog.
  })

  return (
    <div>
      <p>Press cmd+s (or ctrl+s for non mac) to open custom save dialog.</p>
    </div>
  )
}
```

:::caution Warning
Please be aware that there are some hotkeys that we cannot override, because they would interfere with a safe browsing
experience for the user. These depend on the browser.
For example in Chrome, most notably those are `cmd + w` which closes a tab, `cmd + n` for opening a new window and `cmd + t` to open a new tab.
Additionally `cmd + shift + w` (closing all tabs of the current window), `cmd + shift + n` (opening incognito window) and
`cmd + shift + t` (reopen the last closed tab) cannot be overridden.
`cmd + up + 1..9` on the other hand focuses the corresponding tab of the active window and also cannot be overridden.
:::

***

### Disable callback execution

In addition to completely unbinding the hotkey, we can also disable the execution of the callback with setting the `filter`
option. The `filter` key takes a function that is expected to return a boolean value to indicate if the callback should
get executed or not.
In this scenario the hotkey is still active, but the callback won't be called if the filter function returns false.

```jsx
function ExampleComponent() {
  useHotkeys('option+b', () => alert('Callback got executed'), {
    filter: e => {
      return true;
    }
  })

  return (
    <div>
      <p>Pressing 'b' executes the callback, while 'alt+b' won't.</p>
    </div>
  )
}
```

With the `filter` option in mind we can slightly change our save routine override from above:

```jsx
function ExampleComponent() {
  useHotkeys('cmd+s, ctrl+s', () => alert('We saved your progress!'), {
    filter: e => {
      e.preventDefault()

      return true
    }
  })

  return (
    <div>
      <p>Press cmd+s (or ctrl+s for non mac) to open custom save dialog.</p>
    </div>
  )
}
```

This might be preferred if we want to build a custom hook on top of `useHotkeys` that always prevents the default behavior.

***

### Disable default behavior when callback execution is blocked

The above example is sufficient for simple logic to determine whether the callback should be executed.
However, we might come across a scenario where the `filter` function returns `false` so our callback does not get triggered. Maybe
the logic which determines if the callback should be executed is pretty complex, and we don't want to determine inside the
`filter` whether the browser should prevent its default behavior. To simplify this we can use the `filterPreventDefault`
option:

```jsx
function ExampleComponent() {
  useHotkeys('cmd+s, ctrl+s', () => alert('We saved your progress!'), {
    filter: e => {
      // .... some logic to deduce if the callback should get triggered or not

      // If no logic applies, don't trigger the callback
      return false
    },
    filterPreventDefault: true,
  })

  return (
    <div>
      <p>Press cmd+s (or ctrl+s for non mac) to open custom save dialog.</p>
    </div>
  )
}
```

This will cause the browser to prevent opening its page saving dialog even though our callback has not been triggered.

:::warning Changes for version 4
Currently the return values of `filter` and `filterPreventDefault` are counterintuitive. This will change in version 4.
:::

***

### Enable hotkeys on form fields

By default, hotkeys won't trigger when the user is focusing a form field. This is the expected case most of the time.
For example, if we'd listen for the hotkey `'p'` on a review page for apps and a user would try to type `This app is simply
the best` into the review input field, the resulting text would be `This a is simly
the best`. Same with keystrokes that start with `shift + ...` since this normally capitalizes a letter.
So it is good, that `useHotkeys` is smart enough to back off during focused form fields. However, sometimes you still
want hotkeys to be enabled even when the user is focusing on an input field. There might be again the need so save
the users progress. Our previous example would not trigger if the user is focusing a form field. Instead, we have to
enable the hotkey on certain form fields. We can use the `enableOnTags` option for that which takes an array of form tags:

```jsx
function ExampleComponent() {
  useHotkeys('cmd+s, ctrl+s', (e) => {
    e.preventDefault()

    alert('We saved your progress!')
    // ... set up our own saving dialog.
  }, {
    enableOnTags: ['INPUT', 'SELECT', 'TEXTAREA']
  })

  return (
    <div>
      <p>Press cmd+s (or ctrl+s for non mac) to open custom save dialog.</p>
    </div>
  )
}
```

We tell `useHotkeys` that the given keystrokes should be listened to and the callback executed even when the user is currently
focusing an input, select or textarea field.

:::info case-sensitive
Note that the values in the array are case-sensitive. `input` won't work while `INPUT` will. This likey to change in
version 4.
:::

***

### Enable hotkeys on tags leveraging `contentEditable`

The [`contentEditable` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/contenteditable)
allows users to edit text even though it is not part of an input field. For example a `<div>` tag could have the
`contentEditable` attribute. Sometimes we want hotkeys to still trigger, even though a user is focusing an editing a
tags content. A good example for this might be the editor on [medium.com](https://medium.com). `useHotkeys` provides
an option for that:

```jsx
function ExampleComponent() {
  useHotkeys('cmd+b', () => alert('Hotkeys are still working'), {
    enableOnContentEditable: true,
  })

  return (
    <div contentEditable={true}>
      You can edit this text and still use all the active shortcuts.
    </div>
  )
}
```

:::info
Before version `3.3.0`, using a tag with `contentEditable` set to true would not prevent any hotkeys from triggering.
Be sure to update to at least `3.4.0` to leverage this feature.
:::
